#include "Point.h"
#include <iostream>
#include <cassert>
#include <vector>

using namespace std;



// 以指针作为函数参数
void splitFloat(float x, int *intPart, float *fracPart) {
    *intPart = static_cast<int>(x);// 取 x 的整数部分
    *fracPart = x - *intPart;// 取 x 的小数部分
}

// 指向常量的指针做形参
const int N = 6;
void print(const int *p, int n);

void print(const int *p, int n) {
    cout << "{" << *p;
    for (int i = 1; i < n; i++) {
        cout << ", " << *(p+i);
    }
    cout << "}" << endl;
}

int* function() {
    int local = 0;// 非静态局部变量作用域和寿命仅限于本函数体内
    return &local;
}// 函数运行结束时，变量 local 被释放

int* search(int* a, int num) {// 指针 a 指向主函数中定义的数组
    for (int i = 0; i < num; i++) {
        if (a[i] == 0) {
            return &a[i];// 返回的地址指向的元素是在主函数中定义的
        }
    }
}// 函数运行结束时，a[i] 的地址仍有效

int* newintvar() {
    int* p = new int();
    return p;// 返回的地址指向的是动态分配的空间
}// 函数运行结束时，p 中的地址仍有效



int compute(int a, int b, int(*func)(int, int)) {
    return func(a, b);
}

int max(int a, int b) {
    //求最大值
    return ((a > b) ? a : b);
}

int min(int a, int b) {
    //求最小值
    return ((a < b) ? a : b);
}

int sum(int a, int b) {
    // 求和
    return a + b;
}



class Point2 {

public:
    Point2(int x = 0, int y = 0): x(x), y(y) {}
    int getX() const {return x;}
    int getY() const {return y;}

private:
    int x, y;

};


// // this 指针错误例子
// class Fred;// 前向引用声明
// class Barney {
//     Fred x;// 错误：类Fred的声明尚不完善
// };
// class Fred {
//     Barney y;
// };

// // 正确的程序
// class Fred;// 前向引用声明
// class Barney {
//     Fred *x;
// };
// class Fred {
//     Barney y;
// };



class Point3 {

public:
    Point3(): x(0), y(0) {
        cout << "Default Constructor called." << endl;
    }
    Point3(int x, int y): x(x), y(y) {
        cout << "Constructor called." << endl;
    }
    ~Point3() {cout << "Destructor called." << endl;}
    int getX() {return x;}
    int getY() {return y;}
    void move(int newX, int newY) {
        x = newX;
        y = newY;
    }

private:
    int x, y;

};


// 动态数组类
class ArrayOfPoints {

public:
    ArrayOfPoints(int size): size(size) {
        points = new Point3[size];
    }
    ~ArrayOfPoints() {// 奇怪，析构函数会调不起来
        cout << "Deleting..." << endl;
        delete[] points;
    }
    // 深层复制增加方法
    ArrayOfPoints(const ArrayOfPoints& pointsArray);

    // 返回“引用”可以用来操作封装数组对象内部的数组元素。
    // 如果返回“值”则只是回了一个“副本”，
    // 返通过“副本”是无法操作原来数组中的元素的
    Point3& element(int index) {
        assert(index >= 0 && index < size);
        return points[index];
    }

private:
    Point3 *points;// 指向动态数组首地址
    int size;// 数组大小

};
ArrayOfPoints::ArrayOfPoints(const ArrayOfPoints& v) {
    size = v.size;
    points = new Point3[size];
    for (int i = 0; i < size; i++) {
        points[i] = v.points[i];
    }
}



// 计算数组 arr 中元素的平均值
double average(const vector<double> &arr) {
    double sum = 0;
    for (unsigned i = 0; i < arr.size(); i++) {
        sum += arr[i];
    }

    return sum / arr.size();
}



int main() {




    // 对象复制与移动
    //      浅层复制与深层复制 
    //          浅层复制
    //              实现对象间数据元素的一一对应复制。
    //          深层复制
    //              当被复制的对象数据成员是指针类型时，
    //              不是复制该指针成员本身，
    //              而是将指针所指对象进行复制。

    // // 对象的浅层、深层复制
    // int count1;
    // cout << "Please enter the count of points: ";
    // cin >> count1;
    // ArrayOfPoints pointsArray1(count1);// 创建对象数组
    // pointsArray1.element(0).move(5, 10);
    // pointsArray1.element(1).move(15, 20);

    // ArrayOfPoints pointsArray2(pointsArray1);// 创建副本

    // cout << "Copy of pointsArray1:" << endl;
    // cout << "Point_0 of array2: " << pointsArray2.element(0).getX()
    //     << ", " << pointsArray2.element(0).getY() << endl;
    // cout << "Point_1 of array2: " << pointsArray2.element(1).getX()
    //     << ", " << pointsArray2.element(1).getY() << endl;
    // pointsArray1.element(0).move(25, 30);
    // pointsArray1.element(1).move(35, 40);

    // cout << "After the moving of pointsArray1:" << endl;

    // cout << "Point_0 of array2: " << pointsArray2.element(0).getX()
    //     << ", " << pointsArray2.element(0).getY() << endl;
    // cout << "Point_1 of array2: " << pointsArray2.element(1).getX()
    //     << ", " << pointsArray2.element(1).getY() << endl;

















    // vector 对象
    //      为什么需要 vector？ 
    //          封装任何类型的动态数组，自动创建和删除。 
    //          数组下标越界检查。
    //      vector 对象的定义 
    //          vector<元素类型> 数组对象名(数组长度);
    //          例：
    //              vector<int> arr(5) : 建立大小为5的int数组
    //      vector 对象的使用
    //          对数组元素的引用
    //              与普通数组具有相同形式：
    //                  vector对象名 [ 下标表达式 ] 
    //          vector数组对象名不表示数组首地址
    //              获得数组长度 : 用size函数 : 数组对象名.size()

    // // vector 应用举例
    // unsigned n;
    // cout << "n = ";
    // cin >> n;

    // vector<double> arr4(n);// 创建数组对象
    // cout << "Please input " << n << " real numbers:" << endl;
    // for (unsigned i = 0; i < n; i++) {
    //     cin >> arr4[i];
    // }
    
    // cout << "Average = " << average(arr4) << endl;



    // // 基于范围的 for 循环配合 auto 举例
    // vector<int> v = {1, 2, 3};
    // for (auto i = v.begin(); i != v.end(); ++i) {
    //     cout << *i << endl;
    // }

    // for (auto e : v) {
    //     cout << e << endl;
    // }










    // 智能指针
    //      显式管理内存在是能上有优势，但容易出错。
    //      C++11提供智能指针的数据类型，
    //      对垃圾回收技术提供了一些支持，实现一定程度的内存管理
    // C++11 的智能指针
    //      unique_ptr ：不允许多个指针共享资源，
    //              可以用标准库中的move函数转移指针
    //      shared_ptr ：多个指针共享资源
    //      weak_ptr ：可复制shared_ptr，
    //              但其构造或者释放对资源不产生影响










    // 将动态数组封装成类
    //      更加简洁，便于管理
    //      可以在访问数组元素前检查下标是否越界

    // // 动态数组类
    // int count;
    // cout << "Please enter the count of points: ";
    // cin >> count;
    // ArrayOfPoints points(count);// 创建数组对象
    // points.element(0).move(5, 0);// 访问数组元素的成员
    // points.element(1).move(15, 20);// 访问数组元素的成员









    // 动态创建多维数组 
    //      new 类型名T[第1维长度][第2维长度]…;
    //          如果内存申请成功，
    //          new运算返回一个指向新分配内存首地址的指针。
    //          例如：
    //              char (*fp)[3]; 
    //              fp = new char[2][3];

    // // 动态创建多维数组
    // int (*cp)[9][8] = new int[7][9][8];
    // for (int i = 0; i < 7; i++) {
    //     for (int j = 0; j < 9; j++) {
    //         for (int k = 0; k < 8; k++) {
    //             *(*(*(cp + i) + j) + k) = (i * 100 + j * 10 + k);
    //         }
    //     }
    // }
    // for (int i = 0; i < 7; i++) {
    //     for (int j = 0; j < 9; j++) {
    //         for (int k = 0; k < 8; k++) {
    //             cout << cp[i][j][k] << " ";
    //         }
    //         cout << endl;
    //     }
    //     cout << endl;
    // }
    // delete[] cp;








    // 分配和释放动态数组
    //      分配：new 类型名T [ 数组长度 ] 
    //          数组长度可以是任何表达式，在运行时计算
    //      释放：delete[] 数组名p
    //          释放指针p所指向的数组。
    //          p必须是用new分配得到的数组首地址。

    // // 动态创建对象数组举例
    // Point3 *ptr = new Point3[2];// 创建对象数组
    // ptr[0].move(5, 10);// 通过指针访问数组元素的成员
    // ptr[1].move(15, 20);// 通过指针访问数组元素的成员
    // cout << "Deleting..." << endl;
    // delete[] ptr;// 删除整个对象数组










    // 动态内存分配
    //      动态申请内存操作符 new
    //          new 类型名T（初始化参数列表）
    //          功能：在程序执行期间，
    //              申请用于存放T类型对象的内存空间，
    //              并依初值列表赋以初值。
    //          结果值：成功：T类型的指针，指向新分配的内存；
    //              失败：抛出异常。 
    //      释放内存操作符 delete
    //          delete 指针p
    //          功能：释放指针p所指向的内存。p必须是new操作的返回值

    // // 动态创建对象举例
    // cout << "Step one: " << endl;
    // Point3 * ptr1 = new Point3;// 调用默认构造函数
    // delete ptr1;// 删除对象，自动调用析构函数

    // cout << ptr1 << endl;

    // cout << "Step two: " << endl;
    // ptr1 = new Point3(1, 2);
    // delete ptr1;












    // this 指针
    //      指向当前对象自己
    //      隐含于类的每一个非静态成员函数中。
    //      指出成员函数所操作的对象。 
    //          当通过一个对象调用成员函数时，
    //          系统先将该对象的地址赋给this指针，
    //          然后调用成员函数，成员函数对对象的数据成员进行操作时，
    //          就隐含使用了this指针。
    //      例如：Point类的getX函数中的语句：return x; 
    //      相当于： return this->x; 








    // 对象指针
    //      对象指针定义形式: 类名 *对象指针名;
    //          例:
    //              Point a(5,10);
    //              Piont *ptr;
    //              ptr=&a;
    //      通过指针访问对象成员: 对象指针名->成员名
    //          例：
    //              ptr->getx() 相当于 (*ptr).getx();

    // // 使用指针来访问 Point 类的成员
    // Point2 a5(4, 5);
    // Point2 *p1 = &a5;// 定义对象指针，用 a5 的地址初始化
    // cout << p1->getX() << endl;// 用指针访问对象成员
    // cout << a5.getX() << endl;// 用对象名访问对象成员











    // 指向函数的指针
    //      函数指针的定义
    //      定义形式: 存储类型 数据类型 (*函数指针名)();
    //      含义: 函数指针指向的是程序代码存储区。
    //
    //      函数指针的典型用途——实现函数回调
    //          通过函数指针调用的函数
    //              例如将函数的指针作为参数传递给一个函数，
    //              使得在处理相似事件的时候可以灵活的使用不同的方法。
    //          调用者不关心谁是被调用者
    //              需知道存在一个具有特定原型和限制条件的被调用函数。

    // // 函数指针举例
    // int a4, b4, res;
    // // cout << "请输入整数a4 : ";
    // cout << "input a4 : ";
    // cin >> a4;
    // // cout << "请输入整数b4 : ";
    // cout << "input b4 : ";
    // cin >> b4;

    // res = compute(a4, b4, &max);
    // cout << "Max of " << a4 << " and " << b4 << " is " << res << endl;
    // res = compute(a4, b4, &min);
    // cout << "Min of " << a4 << " and " << b4 << " is " << res << endl;
    // res = compute(a4, b4, &sum);
    // cout << "Sum of " << a4 << " and " << b4 << " is " << res << endl;








    // 指针类型的函数
    //      若函数的返回值是指针，该函数就是指针类型的函数
    //      指针函数的定义形式
    //          存储类型 数据类型 *函数名()
    //          { //函数体语句
    //          }

    // // 错误的例子
    // int* function();
    // int* ptr = function();
    // *ptr = 5;// 危险访问


    // // 正确的例子 1
    // int arr3[10];// 主函数中定义的数组
    // int* search(int* a, int num);
    // for (int i = 0; i < 10; i++) {
    //     cin >> arr3[i];
    // }
    // int * zeroptr = search(arr3, 10);// 将主函数中数组的首地址传给子函数

    // // 正确例子 2
    // int* newintvar();
    // int* intptr = newintvar();
    // *intptr = 5;// 访问的是合法有效的地址
    // delete intptr;// 如果忘记在这里释放，会造成内存泄漏









    // int arr1[N];
    // for (int i = 0; i < N; i++) {
    //     cin >> arr1[i];
    // }
    // print(arr1, N);




    

    // // 读入三个浮点数，将整数部分和小数部分分别输出
    // cout << "Enter 3 float point numbers:" << endl;
    // for (int i = 0; i < 3; i++) {
    //     float x, f;
    //     int n;
    //     cin >> x;
    //     splitFloat(x, &n, &f);// 变量地址作为实参
    //     cout << "Integer Part = " << n << " Fraction Part = " << f << endl;
    // }








    // 指针数组
    //      数组的元素是指针型

    // // 利用指针数组存放矩阵
    // int line1[] = {1, 0, 0};// 矩阵的第一行
    // int line2[] = {0, 1, 0};// 矩阵的第二行
    // int line3[] = {0, 0, 1};// 矩阵的第三行

    // // 定义整型指针数组并初始化
    // int *pLine[3] = {line1, line2, line3};
    // cout << "Matrix test:" << endl;
    // // 输出矩阵
    // for (int i = 0; i < 3; i++) {
    //     for (int j = 0; j < 3; j++) {
    //         cout << pLine[i][j] << " ";
    //     }
    //     cout << endl;
    // }





    
    // int a2[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
    // // 使用数组名和下标访问数组元素
    // for (int i = 0; i < 10; i++) {
    //     cout << a2[i] << " ";
    // }
    // cout << endl;

    // // 使用数组名和指针运算访问数组元素
    // for (int i = 0; i < 10; i++) {
    //     cout << *(a2+i) << " ";
    // }
    // cout << endl;

    // // 使用指针变量访问数组元素
    // for (int *p = a2; p < (a2 + 10); p++) {
    //     cout << *p << " ";
    // }
    // cout << endl;



    // 指针类型的常量 
    //      若声明指针常量，则指针本身的值不能被改变

    // int a1;
    // int b1;
    // int * const p2 = &a1;
    // // p2 = &b1;// 错误，p2 是指针常量，值不能改变


    // 指向常量的指针
    //      不能通过指向常量的指针改变所指对象的值，
    //      但指针本身可以改变，可以指向另外的对象
    
    // int a;
    // const int *p1 = &a;// p1 是指向常量的指针
    // int b;
    // p1 = &b;// 正确，p1 本身的值可以改变
    // // *p1 = 1;//编译时出错，不能通过 p1 改变所指的对象





    // 指针

    // // void voidObject;// 错误，不能声明 void 类型的变量
    // void *pv;// 正确，可以声明 void 类型的指针
    // int i = 5;
    // pv = &i;// void 类型指针指向整型变量
    // int *pint = static_cast<int *>(pv);// void 指针转换为 int 指针
    // cout << "*pint = " << *pint << endl;


    // int i;// 定义 int 型数 i
    // int *ptr = &i;// 取 i 的地址赋给ptr
    // i = 10;// int 型数赋初值
    // cout << "i = " << i << endl;//输出 int 型数的值
    // cout << "*ptr = " << *ptr << endl;// 输出 int 型指针所指地址的内容 




    

    // //基于范围的 for 循环
    // int arr[3] = {1, 2, 3};
    // int *p;
    // for (p = arr; p < arr + sizeof(arr) / sizeof(int); ++p) {
    //     *p += 2;
    //     cout << *p << endl;
    // }

    // for (int& e : arr) {
    //     e += 2;
    //     cout << e << endl;
    // }





    // cout << "Entering main..." << endl;
    // Point1 a[2];
    // for (int i = 0; i < 2; i++) {
    //     a[i].move(i + 10, i + 20);
    // }
    // cout << "Exiting main..." << endl;





    system("pause");

    return 0;
}